package com.cl.code.common.utils;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * MD5 工具类，用于对字符串、字节数组、输入流进行 MD5 摘要计算。
 * 使用标准 Java 21 API 编写。
 */
public final class Md5Utils {

    private Md5Utils() {
        // 工具类禁止实例化
    }

    /**
     * 计算字符串的 MD5 摘要（小写十六进制）。
     *
     * @param input 输入字符串，使用 UTF-8 编码
     * @return MD5 值（小写十六进制）
     */
    public static String md5(String input) {
        return md5(input, false);
    }

    /**
     * 计算字符串的 MD5 摘要（可选大小写十六进制）。
     *
     * @param input     输入字符串，使用 UTF-8 编码
     * @param upperCase 是否输出大写十六进制
     * @return MD5 值
     */
    public static String md5(String input, boolean upperCase) {
        byte[] bytes = input.getBytes(StandardCharsets.UTF_8);
        return md5(bytes, upperCase);
    }

    /**
     * 计算字节数组的 MD5 摘要（小写十六进制）。
     *
     * @param data 原始字节数据
     * @return MD5 值（小写十六进制）
     */
    public static String md5(byte[] data) {
        return md5(data, false);
    }

    /**
     * 计算字节数组的 MD5 摘要（可选大小写十六进制）。
     *
     * @param data      原始字节数据
     * @param upperCase 是否输出大写十六进制
     * @return MD5 值
     */
    public static String md5(byte[] data, boolean upperCase) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] digest = md.digest(data);
            return bytesToHex(digest, upperCase);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("MD5 algorithm not available", e);
        }
    }

    /**
     * 计算输入流的 MD5 摘要（小写十六进制）。
     * 推荐用于大文件计算，自动分段读取。
     *
     * @param inputStream 输入流（调用方负责关闭）
     * @return MD5 值（小写十六进制）
     */
    public static String md5(InputStream inputStream) {
        return md5(inputStream, false);
    }

    /**
     * 计算输入流的 MD5 摘要（可选大小写十六进制）。
     *
     * @param inputStream 输入流（调用方负责关闭）
     * @param upperCase   是否输出大写十六进制
     * @return MD5 值
     */
    public static String md5(InputStream inputStream, boolean upperCase) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                md.update(buffer, 0, bytesRead);
            }
            byte[] digest = md.digest();
            return bytesToHex(digest, upperCase);
        } catch (Exception e) {
            throw new RuntimeException("Failed to compute MD5 from input stream", e);
        }
    }

    /**
     * 将字节数组转换为十六进制字符串。
     *
     * @param bytes     原始字节数组
     * @param upperCase 是否使用大写字母
     * @return 十六进制字符串
     */
    private static String bytesToHex(byte[] bytes, boolean upperCase) {
        StringBuilder sb = new StringBuilder(bytes.length * 2);
        for (byte b : bytes) {
            sb.append(String.format(upperCase ? "%02X" : "%02x", b));
        }
        return sb.toString();
    }
}
